using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace RMD.quickswitch
{
    public partial class MainForm : Form
    {
        private const int WM_KEYDOWN = 0x0100;
        private WindowManager m_winmgr;

        private IntPtr m_hhook;

        public MainForm()
        {
            InitializeComponent();

            m_winmgr = new WindowManager();
            Win32.RegisterHotKey(this.Handle, 218, (uint)(Win32.MOD_KEYS.MOD_ALT | Win32.MOD_KEYS.MOD_CONTROL), (uint)Keys.S);
            // Disable global hook for now
            //m_hhook = Win32.SetWindowsHookEx((int)Win32.HookType.WH_KEYBOARD_LL, new Win32.HookProc(CoreHookProc),
            //    Win32.GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName),
            //    0);
        }

        // Default filter function
        public int CoreHookProc(int code, IntPtr wParam, IntPtr lParam)
        {
            if (code < 0)
                return Win32.CallNextHookEx(m_hhook, code, wParam, lParam);

            if (code >= 0 && wParam == (IntPtr)WM_KEYDOWN)
            {
                int vkCode = Marshal.ReadInt32(lParam);
                //Debug.WriteLine(vkCode); Debug.WriteLine(Keys.LWin|Keys.J);
                if(Win32.GetAsyncKeyState(Keys.LWin) < 0 && vkCode == (int)Keys.J)
                {
                    Debug.WriteLine((Keys)vkCode);
                }
                if (Win32.GetAsyncKeyState(Keys.LWin) < 0 && vkCode == (int)Keys.K)
                {
                    Debug.WriteLine((Keys)vkCode);
                }
            }

            // Yield to the next hook in the chain
            return Win32.CallNextHookEx(m_hhook, code, wParam, lParam);
        }

        private void tbSearchTerm_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
        {
            switch(e.KeyCode)
            {
                case Keys.Enter:
                    //bool rc = Win32.EnumWindows(new Win32.EnumWindowsProc(OnEnumWindow), IntPtr.Zero);
                    if (this.lvWindows.Items.Count == 1) // if no matching window was found
                    {
                        foreach (WindowDesc w in m_winmgr.WindowList)
                        {
                            if (string.Compare(w.m_title, this.lvWindows.Items[0].Text, true) == 0)
                            {
                                this.Hide();
                                this.m_winmgr.ActiveWindow(w.m_hWnd);
                            }
                        }
                    }
                    else
                    {
                        this.lvWindows.Focus();
                        if (this.lvWindows.Items.Count > 0)
                            this.lvWindows.Items[0].Selected = true;
                    }
                    break;
                case Keys.OemOpenBrackets:
                    if (e.Control) // use Ctrl+[ to simulate escape key (vim shortcut key)
                        this.Hide();
                    break;
                case Keys.C:
                    if (e.Control) // use Ctrl+C to hide current window
                        this.Hide();
                    break;
                case Keys.U:
                    if (e.Control) // use Ctrl+u to delete to beginning
                        tbSearchTerm.Text = tbSearchTerm.Text.Substring(tbSearchTerm.SelectionStart);
                    break;
                case Keys.K:
                    if (e.Control) // use Ctrl+k to delete to end
                        tbSearchTerm.Text = tbSearchTerm.Text.Substring(0, tbSearchTerm.SelectionStart);
                    break;
                case Keys.E:
                    if (e.Control) // use Ctrl+E to move to the end of text
                        tbSearchTerm.SelectionStart = tbSearchTerm.Text.Length;
                    break;
                case Keys.F:
                    if (e.Control) // use Ctrl+F to move forward
                    {
                        tbSearchTerm.SelectionLength = 0;
                        tbSearchTerm.SelectionStart += tbSearchTerm.Text.Length > tbSearchTerm.SelectionStart ? 1 : 0;
                    }   
                    break;
                case Keys.B:
                    if (e.Control) // use Ctrl+B to move backword
                    {
                        tbSearchTerm.SelectionLength = 0;
                        tbSearchTerm.SelectionStart -= tbSearchTerm.SelectionStart > 0 ? 1 : 0;
                    }
                    break;
                case Keys.D:
                    if (e.Control) // use Ctrl+D to delete a charactre forward
                    {
                        tbSearchTerm.SelectionLength = 0;
                        int start = tbSearchTerm.SelectionStart;
                        string cur = tbSearchTerm.Text;
                        tbSearchTerm.Text = cur.Substring(0, start)
                            + (cur.Length >= (start + 1) ? cur.Substring(start + 1) : "");
                        tbSearchTerm.SelectionStart = start;
                    }
                    break;
                case Keys.H:
                    if (e.Control) // use Ctrl+H to delete a character backward
                    {
                        tbSearchTerm.SelectionLength = 0;
                        int start = tbSearchTerm.SelectionStart;
                        string cur = tbSearchTerm.Text;
                        tbSearchTerm.Text = (start > 1 ? cur.Substring(0, start) : "")
                            + cur.Substring(start);
                        tbSearchTerm.SelectionStart = start;
                    }
                    break;
                case Keys.Escape:
                    this.Hide();
                    break;
                case Keys.Down:
                    this.lvWindows.Focus();
                    if(this.lvWindows.Items.Count > 0)
                        this.lvWindows.Items[0].Selected = true;
                    break;
                default:
                    break;
            }

        }

        private void ShowMainWindow(bool focusSearchTerm)
        {
            this.Show();
            this.Activate();
            this.BringToFront();
            if (focusSearchTerm)
            {
                this.tbSearchTerm.Focus();
                this.tbSearchTerm.SelectAll();
            }
        }

        protected override void WndProc(ref Message m)
        {
            if (m.Msg == Win32.WM_HOTKEY && 
                ((Keys)(((int)m.LParam >> 16) & 0xFFFF) == Keys.S))
            {
                if (this.Visible)
                {
                    this.ShowMainWindow(true);
                }
                else
                {
                    this.ShowMainWindow(false);
                }
            } 
            base.WndProc(ref m);
        }

        private void MainForm_Activated(object sender, EventArgs e)
        {
            this.lvWindows.Items.Clear();
            this.tbSearchTerm.Focus();
            this.tbSearchTerm.SelectAll();
            m_winmgr.RefreshWindowList();
            FilterWindows();
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            this.Hide();
            e.Cancel = true;
        }

        private void miExit_Click(object sender, EventArgs e)
        {
            System.Environment.Exit(0);
        }

        private void FilterWindows()
        {
            this.lvWindows.Items.Clear();
            foreach (WindowDesc w in m_winmgr.WindowList)
            {
                if (w.m_title.ToLower().Contains(tbSearchTerm.Text.Trim().ToLower()))
                {
                    this.lvWindows.Items.Add(new ListViewItem(w.m_title));
                }
            }
        }

        private void tbSearchTerm_TextChanged(object sender, EventArgs e)
        {
            FilterWindows();
        }

        private void lvWindows_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
        {
            int selected_index = lvWindows.SelectedIndices.Count > 0 ? lvWindows.SelectedIndices[0] : -1;
            switch (e.KeyCode)
            {
                case Keys.Enter:
                    foreach (WindowDesc w in m_winmgr.WindowList)
                    {
                        if (selected_index >= 0 && string.Compare(w.m_title, this.lvWindows.SelectedItems[0].Text, true) == 0)
                        {
                            this.Hide();
                            this.m_winmgr.ActiveWindow(w.m_hWnd);
                        }
                    }
                    break;
                case Keys.OemOpenBrackets:
                    if (e.Control) // use Ctrl+[ to simulate escape key (vim shortcut key)
                        this.Hide();
                    break;
                case Keys.P:
                    if (e.Control) // use Ctrl+[ to simulate escape key (vim shortcut key)
                    {
                        if (selected_index > 0)
                            lvWindows.Items[selected_index - 1].Selected = true;
                    }
                    break;
                case Keys.N:
                    if (e.Control) // use Ctrl+[ to simulate escape key (vim shortcut key)
                    {
                        if (selected_index < lvWindows.Items.Count - 1)
                            lvWindows.Items[selected_index + 1].Selected = true;
                    }
                    break;
                case Keys.Escape:
                    this.Hide();
                    break;
                default:
                    break;
            }
        }

        private void cmsNotificationMenu_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            if (e.ClickedItem == tsmiExit)
            {
                System.Environment.Exit(0);
                return;
            }
            if (e.ClickedItem == tsmiHideIcon)
            {
                niMain.Visible = false;
            }
            if (e.ClickedItem == tsmiShow)
            {
                this.ShowMainWindow(true);
            }
        }

        private void miToggleIcon_Click(object sender, EventArgs e)
        {
            niMain.Visible = !niMain.Visible;
        }

        private void niMain_DoubleClick(object sender, EventArgs e)
        {
            this.ShowMainWindow(true);
        }
    }
}